home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / LIB / GLUT / capturexfont.c next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  10.8 KB  |  353 lines

  1.  
  2. /* Copyright (c) Mark J. Kilgard, 1994. */
  3.  
  4. /* This program is freely distributable without licensing fees 
  5.    and is provided without guarantee or warrantee expressed or 
  6.    implied. This program is -not- in the public domain. */
  7.  
  8. /* capturexfont.c connects to an X server and downloads a
  9.    bitmap font from which a C source file is generated,
  10.    encoding  the font for GLUT's use. Example usage:
  11.    capturexfont.c 9x15 glutBitmap9By15 > glut_9x15.c */
  12.  
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <ctype.h>
  17. #include <GL/gl.h>
  18. #include <X11/Xlib.h>
  19. #include <X11/Xutil.h>
  20.  
  21. #define MAX_GLYPHS_PER_GRAB 512  /* This is big enough for 2^9
  22.                                     glyph character sets */
  23.  
  24. static void
  25. outputChar(int num, int width, int height,
  26.   int xoff, int yoff, int advance, int data)
  27. {
  28.   if (width == 0 || height == 0) {
  29.     printf("#ifdef _WIN32\n");
  30.     printf("/* XXX Work around Microsoft OpenGL 1.1 bug where glBitmap with\n");
  31.     printf("   a height or width of zero does not advance the raster position\n");
  32.     printf("   as specified by OpenGL. (Cosmo OpenGL does not have this bug.) */\n");
  33.     printf("static const GLubyte ch%ddata[] = { 0x0 };\n", num);
  34.     printf("static const BitmapCharRec ch%d = {", num);
  35.     printf("%d,", 0);
  36.     printf("%d,", 0);
  37.     printf("%d,", xoff);
  38.     printf("%d,", yoff);
  39.     printf("%d,", advance);
  40.     printf("ch%ddata", num);
  41.     printf("};\n");
  42.     printf("#else\n");
  43.   }
  44.   printf("static const BitmapCharRec ch%d = {", num);
  45.   printf("%d,", width);
  46.   printf("%d,", height);
  47.   printf("%d,", xoff);
  48.   printf("%d,", yoff);
  49.   printf("%d,", advance);
  50.   if (data) {
  51.     printf("ch%ddata", num);
  52.   } else {
  53.     printf("0");
  54.   }
  55.   printf("};\n");
  56.   if (width == 0 || height == 0) {
  57.     printf("#endif\n");
  58.   }
  59.   printf("\n");
  60. }
  61.  
  62. /* Can't just use isprint because it only works for the range
  63.    of ASCII characters (ie, TRUE for isascii) and capturexfont
  64.    might be run on 16-bit fonts. */
  65. #define PRINTABLE(ch)  (isascii(ch) ? isprint(ch) : 0)
  66.  
  67. void
  68. captureXFont(Display * dpy, Font font, char *xfont, char *name)
  69. {
  70.   int first, last, count;
  71.   int cnt, len;
  72.   Pixmap offscreen;
  73.   Window drawable;
  74.   XFontStruct *fontinfo;
  75.   XImage *image;
  76.   GC xgc;
  77.   XGCValues values;
  78.   int width, height;
  79.   int i, j, k;
  80.   XCharStruct *charinfo;
  81.   XChar2b character;
  82.   GLubyte *bitmapData;
  83.   int x, y;
  84.   int spanLength;
  85.   int charWidth, charHeight, maxSpanLength, pixwidth;
  86.   int grabList[MAX_GLYPHS_PER_GRAB];
  87.   int glyphsPerGrab = MAX_GLYPHS_PER_GRAB;
  88.   int numToGrab;
  89.   int rows, pages, byte1, byte2, index;
  90.   int nullBitmap;
  91.  
  92.   drawable = RootWindow(dpy, DefaultScreen(dpy));
  93.  
  94.   fontinfo = XQueryFont(dpy, font);
  95.   pages = fontinfo->max_char_or_byte2 - fontinfo->min_char_or_byte2 + 1;
  96.   first = (fontinfo->min_byte1 << 8) + fontinfo->min_char_or_byte2;
  97.   last = (fontinfo->max_byte1 << 8) + fontinfo->max_char_or_byte2;
  98.   count = last - first + 1;
  99.  
  100.   width = fontinfo->max_bounds.rbearing -
  101.     fontinfo->min_bounds.lbearing;
  102.   height = fontinfo->max_bounds.ascent +
  103.     fontinfo->max_bounds.descent;
  104.   /* 16-bit fonts have more than one row; indexing into
  105.      per_char is trickier. */
  106.   rows = fontinfo->max_byte1 - fontinfo->min_byte1 + 1;
  107.  
  108.   maxSpanLength = (width + 7) / 8;
  109.   /* For portability reasons we don't use alloca for
  110.      bitmapData, but we could. */
  111.   bitmapData = malloc(height * maxSpanLength);
  112.   /* Be careful determining the width of the pixmap; the X
  113.      protocol allows pixmaps of width 2^16-1 (unsigned short
  114.      size) but drawing coordinates max out at 2^15-1 (signed
  115.      short size).  If the width is too large, we need to limit
  116.      the glyphs per grab. */
  117.   if ((glyphsPerGrab * 8 * maxSpanLength) >= (1 << 15)) {
  118.     glyphsPerGrab = (1 << 15) / (8 * maxSpanLength);
  119.   }
  120.   pixwidth = glyphsPerGrab * 8 * maxSpanLength;
  121.   offscreen = XCreatePixmap(dpy, drawable, pixwidth, height, 1);
  122.  
  123.   values.font = font;
  124.   values.background = 0;
  125.   values.foreground = 0;
  126.   xgc = XCreateGC(dpy, offscreen,
  127.     GCFont | GCBackground | GCForeground, &values);
  128.   XFillRectangle(dpy, offscreen, xgc, 0, 0,
  129.     8 * maxSpanLength * glyphsPerGrab, height);
  130.   XSetForeground(dpy, xgc, 1);
  131.  
  132.   numToGrab = 0;
  133.   if (fontinfo->per_char == NULL) {
  134.     charinfo = &(fontinfo->min_bounds);
  135.     charWidth = charinfo->rbearing - charinfo->lbearing;
  136.     charHeight = charinfo->ascent + charinfo->descent;
  137.     spanLength = (charWidth + 7) / 8;
  138.   }
  139.   printf("\n/* GENERATED FILE -- DO NOT MODIFY */\n\n");
  140.   printf("#include \"glutbitmap.h\"\n\n");
  141.   for (i = first; count; i++, count--) {
  142.     int undefined;
  143.     if (rows == 1) {
  144.       undefined = (fontinfo->min_char_or_byte2 > i ||
  145.         fontinfo->max_char_or_byte2 < i);
  146.     } else {
  147.       byte2 = i & 0xff;
  148.       byte1 = i >> 8;
  149.       undefined = (fontinfo->min_char_or_byte2 > byte2 ||
  150.         fontinfo->max_char_or_byte2 < byte2 ||
  151.         fontinfo->min_byte1 > byte1 ||
  152.         fontinfo->max_byte1 < byte1);
  153.  
  154.     }
  155.     if (undefined) {
  156.       goto PossiblyDoGrab;
  157.     }
  158.     if (fontinfo->per_char != NULL) {
  159.       if (rows == 1) {
  160.         index = i - fontinfo->min_char_or_byte2;
  161.       } else {
  162.         byte2 = i & 0xff;
  163.         byte1 = i >> 8;
  164.         index =
  165.           (byte1 - fontinfo->min_byte1) * pages +
  166.           (byte2 - fontinfo->min_char_or_byte2);
  167.       }
  168.       charinfo = &(fontinfo->per_char[index]);
  169.       charWidth = charinfo->rbearing - charinfo->lbearing;
  170.       charHeight = charinfo->ascent + charinfo->descent;
  171.       if (charWidth == 0 || charHeight == 0) {
  172.         if (charinfo->width != 0) {
  173.           /* Still must move raster pos even if empty character 
  174.  
  175.            */
  176.           outputChar(i, 0, 0, 0, 0, charinfo->width, 0);
  177.         }
  178.         goto PossiblyDoGrab;
  179.       }
  180.     }
  181.     grabList[numToGrab] = i;
  182.     character.byte2 = i & 255;
  183.     character.byte1 = i >> 8;
  184.  
  185.     /* XXX We could use XDrawImageString16 which would also
  186.        paint the backing rectangle but X server bugs in some
  187.        scalable font rasterizers makes it more effective to do
  188.        XFillRectangles to clear the pixmap and then
  189.        XDrawImage16 for the text.  */
  190.     XDrawString16(dpy, offscreen, xgc,
  191.       -charinfo->lbearing + 8 * maxSpanLength * numToGrab,
  192.       charinfo->ascent, &character, 1);
  193.  
  194.     numToGrab++;
  195.  
  196.   PossiblyDoGrab:
  197.  
  198.     if (numToGrab >= glyphsPerGrab || count == 1) {
  199.       image = XGetImage(dpy, offscreen,
  200.         0, 0, pixwidth, height, 1, XYPixmap);
  201.       for (j = numToGrab - 1; j >= 0; j--) {
  202.         if (fontinfo->per_char != NULL) {
  203.           byte2 = grabList[j] & 0xff;
  204.           byte1 = grabList[j] >> 8;
  205.           index =
  206.             (byte1 - fontinfo->min_byte1) * pages +
  207.             (byte2 - fontinfo->min_char_or_byte2);
  208.           charinfo = &(fontinfo->per_char[index]);
  209.           charWidth = charinfo->rbearing - charinfo->lbearing;
  210.           charHeight = charinfo->ascent + charinfo->descent;
  211.           spanLength = (charWidth + 7) / 8;
  212.         }
  213.         memset(bitmapData, 0, height * spanLength);
  214.         for (y = 0; y < charHeight; y++) {
  215.           for (x = 0; x < charWidth; x++) {
  216.             if (XGetPixel(image, j * maxSpanLength * 8 + x,
  217.                 charHeight - 1 - y)) {
  218.               /* Little endian machines (such as DEC Alpha)
  219.                  could  benefit from reversing the bit order
  220.                  here and changing the GL_UNPACK_LSB_FIRST
  221.                  parameter in glutBitmapCharacter to GL_TRUE. */
  222.               bitmapData[y * spanLength + x / 8] |=
  223.                 (1 << (7 - (x & 7)));
  224.             }
  225.           }
  226.         }
  227.         if (PRINTABLE(grabList[j])) {
  228.           printf("/* char: 0x%x '%c' */\n\n",
  229.             grabList[j], grabList[j]);
  230.         } else {
  231.           printf("/* char: 0x%x */\n\n", grabList[j]);
  232.         }
  233.  
  234.         /* Determine if the bitmap is null. */
  235.         nullBitmap = 1;
  236.         len = (charinfo->ascent + charinfo->descent) *
  237.           ((charinfo->rbearing - charinfo->lbearing + 7) / 8);
  238.         cnt = 0;
  239.         while (cnt < len) {
  240.           for (k = 0; k < 16 && cnt < len; k++, cnt++) {
  241.             if (bitmapData[cnt] != 0) {
  242.               nullBitmap = 0;
  243.             }
  244.           }
  245.         }
  246.  
  247.         if (!nullBitmap) {
  248.           printf("static const GLubyte ch%ddata[] = {\n", grabList[j]);
  249.           len = (charinfo->ascent + charinfo->descent) *
  250.             ((charinfo->rbearing - charinfo->lbearing + 7) / 8);
  251.           cnt = 0;
  252.           while (cnt < len) {
  253.             for (k = 0; k < 16 && cnt < len; k++, cnt++) {
  254.               printf("0x%x,", bitmapData[cnt]);
  255.             }
  256.             printf("\n");
  257.           }
  258.           printf("};\n\n");
  259.         } else {
  260.           charWidth = 0;
  261.           charHeight = 0;
  262.         }
  263.  
  264.         outputChar(grabList[j], charWidth, charHeight,
  265.           -charinfo->lbearing, charinfo->descent,
  266.           charinfo->width, !nullBitmap);
  267.       }
  268.       XDestroyImage(image);
  269.       numToGrab = 0;
  270.       if (count > 0) {
  271.         XSetForeground(dpy, xgc, 0);
  272.         XFillRectangle(dpy, offscreen, xgc, 0, 0,
  273.           8 * maxSpanLength * glyphsPerGrab, height);
  274.         XSetForeground(dpy, xgc, 1);
  275.       }
  276.     }
  277.   }
  278.   XFreeGC(dpy, xgc);
  279.   XFreePixmap(dpy, offscreen);
  280.   /* For portability reasons we don't use alloca for
  281.      bitmapData, but we could. */
  282.   free(bitmapData);
  283.  
  284.   printf("static const BitmapCharRec * const chars[] = {\n");
  285.   for (i = first; i <= last; i++) {
  286.     int undefined;
  287.     byte2 = i & 0xff;
  288.     byte1 = i >> 8;
  289.     undefined = (fontinfo->min_char_or_byte2 > byte2 ||
  290.       fontinfo->max_char_or_byte2 < byte2 ||
  291.       fontinfo->min_byte1 > byte1 ||
  292.       fontinfo->max_byte1 < byte1);
  293.     if (undefined) {
  294.       printf("0,\n");
  295.     } else {
  296.       if (fontinfo->per_char != NULL) {
  297.         if (rows == 1) {
  298.           index = i - fontinfo->min_char_or_byte2;
  299.         } else {
  300.           byte2 = i & 0xff;
  301.           byte1 = i >> 8;
  302.           index =
  303.             (byte1 - fontinfo->min_byte1) * pages +
  304.             (byte2 - fontinfo->min_char_or_byte2);
  305.         }
  306.         charinfo = &(fontinfo->per_char[index]);
  307.         charWidth = charinfo->rbearing - charinfo->lbearing;
  308.         charHeight = charinfo->ascent + charinfo->descent;
  309.         if (charWidth == 0 || charHeight == 0) {
  310.           if (charinfo->width == 0) {
  311.             printf("0,\n");
  312.             continue;
  313.           }
  314.         }
  315.       }
  316.       printf("&ch%d,\n", i);
  317.     }
  318.   }
  319.   printf("};\n\n");
  320.   printf("const BitmapFontRec %s = {\n", name);
  321.   printf("\"%s\",\n", xfont);
  322.   printf("%d,\n", last - first + 1);
  323.   printf("%d,\n", first);
  324.   printf("chars\n");
  325.   printf("};\n\n");
  326.   XFreeFont(dpy, fontinfo);
  327. }
  328.  
  329. int
  330. main(int argc, char **argv)
  331. {
  332.   Display *dpy;
  333.   Font font;
  334.  
  335.   if (argc != 3) {
  336.     fprintf(stderr, "usage: capturexfont XFONT NAME\n");
  337.     exit(1);
  338.   }
  339.   dpy = XOpenDisplay(NULL);
  340.   if (dpy == NULL) {
  341.     fprintf(stderr, "capturexfont: could not open X display\n");
  342.     exit(1);
  343.   }
  344.   font = XLoadFont(dpy, argv[1]);
  345.   if (font == None) {
  346.     fprintf(stderr, "capturexfont: bad font\n");
  347.     exit(1);
  348.   }
  349.   captureXFont(dpy, font, argv[1], argv[2]);
  350.   XCloseDisplay(dpy);
  351.   return 0;
  352. }
  353.